package top.broncho.lottery.ui.history

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.paging.PagedListAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import org.jetbrains.anko.design.snackbar
import top.broncho.lottery.R
import top.broncho.lottery.data.paging.*
import top.broncho.lottery.databinding.*
import top.broncho.lottery.model.history.LotteryRes

class HistoryAdapter(private val retryCallback: () -> Unit) :
    PagedListAdapter<LotteryRes, RecyclerView.ViewHolder>(diffCallback) {

    private var state: LoadingState = Succeed(true)

    override fun getItemViewType(position: Int): Int {
        return if (isShowLastRow() && position == itemCount - 1) {
            R.layout._loading_more_layout
        } else if (isShowEmptyView()) {
            R.layout._loading_layout_empty
        } else if (isShowFailedView()) {
            R.layout._loading_layout_error
        } else if (isShowLoadingView()) {
            R.layout.layout_loading
        } else {
            R.layout.layout_history_item
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return when (viewType) {
            R.layout.layout_history_item ->
                ViewHolder(LayoutHistoryItemBinding.inflate(inflater, parent, false))
            R.layout._loading_more_layout ->
                LoadingMoreViewHolder(LoadingMoreLayoutBinding.inflate(inflater, parent, false))
            R.layout._loading_layout_error ->
                ErrorViewHolder(LoadingLayoutErrorBinding.inflate(inflater, parent, false))
            R.layout.layout_loading ->
                LoadingViewHolder(LayoutLoadingBinding.inflate(inflater, parent, false))
            else ->
                EmptyViewHolder(LoadingLayoutEmptyBinding.inflate(inflater, parent, false))
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (getItemViewType(position)) {
            R.layout.layout_history_item -> getItem(position)?.let {
                (holder as ViewHolder).apply {
                    bind(createOnClickListener(it), it)
                    itemView.tag = it
                }
            }
//            R.layout.layout_loading -> (holder as LoadingViewHolder).apply {
//                bind()
//            }
//            R.layout._loading_layout_empty -> (holder as EmptyViewHolder).apply {
//                bind()
//            }
            R.layout._loading_layout_error -> (holder as ErrorViewHolder).apply {
                bind(state as Failed, retryCallback)
            }
            R.layout._loading_more_layout -> (holder as LoadingMoreViewHolder).apply {
                bind(state, retryCallback)
            }
        }
    }

    private fun createOnClickListener(item: LotteryRes?): View.OnClickListener {
        return View.OnClickListener {
            item?.run {
                it.snackbar(
                    it.context.getString(
                        R.string.lottery_title_format,
                        item.lottery_no,
                        item.lottery_date
                    )
                )
            }
        }
    }

    class ViewHolder(private val binding: LayoutHistoryItemBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind(listener: View.OnClickListener, item: LotteryRes?) {
            binding.apply {
                clickListener = listener
                lottery = item
                array = item?.lottery_res?.split(",")
                executePendingBindings()
            }
        }
    }

    class LoadingViewHolder(private val binding: LayoutLoadingBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind() {
            binding.apply {
                shimmerLayout.startShimmerAnimation()
                executePendingBindings()
            }
        }
    }

    class EmptyViewHolder(private val binding: LoadingLayoutEmptyBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind() {
            binding.apply {
                executePendingBindings()
            }
        }
    }

    class ErrorViewHolder(private val binding: LoadingLayoutErrorBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind(
            listState: Failed,
            retryCallback: () -> Unit
        ) {
            binding.apply {
                errorTitle.text = listState.t?.message
                retryButton.setOnClickListener {
                    retryCallback()
                }
                executePendingBindings()
            }
        }
    }

    class LoadingMoreViewHolder(private val binding: LoadingMoreLayoutBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind(
            listState: LoadingState,
            retryCallback: () -> Unit
        ) {
            binding.apply {
                when (listState) {
                    is Loading -> {
                        loadMoreLoadingView.visibility = View.VISIBLE
                        loadMoreLoadFailView.visibility = View.GONE
                        loadMoreLoadEndView.visibility = View.GONE
                    }
                    is Failed -> {
                        loadMoreLoadingView.visibility = View.GONE
                        loadMoreLoadFailView.visibility = View.VISIBLE
                        loadMoreLoadEndView.visibility = View.GONE
                        loadMoreLoadFailView.setOnClickListener {
                            retryCallback()
                        }
                    }
                    else -> {
                        loadMoreLoadingView.visibility = View.GONE
                        loadMoreLoadFailView.visibility = View.GONE
                        loadMoreLoadEndView.visibility = View.VISIBLE
                    }
                }
                executePendingBindings()
            }
        }
    }

    //是否显示加载视图
    private fun isShowLastRow() = when (state) {
        is Loading, is Failed, is NotMore -> !state.isInit
        else -> false
    }

    //是否显示空视图
    private fun isShowEmptyView() =
        super.getItemCount() == 0 && state is Empty && state.isInit

    private fun isShowFailedView() =
        super.getItemCount() == 0 && state is Failed && state.isInit

    private fun isShowLoadingView() = false
    //super.getItemCount() == 0 && state is Loading && state.isInit

    override fun getItemCount() = super.getItemCount() +
            if (isShowLastRow() || isShowEmptyView() || isShowFailedView() || isShowLoadingView()) 1 else 0

    fun setLoadingState(loadingState: LoadingState) {
        //更新分页加载状态
        if (state == loadingState)
            return
        state = loadingState

        if (loadingState.isInit) {
            notifyDataSetChanged()
        } else {
            val lastItemCount = itemCount
            when {
                itemCount - 1 == lastItemCount -> {
                    notifyItemInserted(lastItemCount - 1)
                }
                itemCount + 1 == lastItemCount -> {
                    notifyItemRemoved(lastItemCount - 1)
                }
                itemCount == lastItemCount -> {
                    notifyItemChanged(lastItemCount - 1)
                }
            }
        }
    }

    companion object {
        /**
         * This diff callback informs the PagedListAdapter how to compute list differences when new
         * PagedLists arrive.
         * <p>
         * When you add a Cheese with the 'Add' button, the PagedListAdapter uses diffCallback to
         * detect there's only a single item difference from before, so it only needs to animate and
         * rebind a single view.
         *
         * @see androidx.recyclerview.widget.DiffUtil
         */
        private val diffCallback = object : DiffUtil.ItemCallback<LotteryRes>() {
            override fun areItemsTheSame(oldItem: LotteryRes, newItem: LotteryRes): Boolean =
                oldItem.lottery_no == newItem.lottery_no

            /**
             * Note that in kotlin, == checking on data classes compares all contents, but in Java,
             * typically you'll implement Object#equals, and use it to compare object contents.
             */
            override fun areContentsTheSame(oldItem: LotteryRes, newItem: LotteryRes): Boolean =
                oldItem == newItem
        }
    }
}